package com.itsm.example.statemachine.factory;

import com.itsm.example.audit.pojo.enums.StateMachineEnum;
import com.itsm.example.audit.pojo.state.AuditState;
import com.itsm.example.statemachine.bo.ItsmContext;
import com.itsm.example.statemachine.bo.ItsmEvent;
import com.itsm.example.statemachine.bo.ItsmState;
import com.itsm.statemachine.StateMachine;
import com.itsm.statemachine.StateMachineFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author benym
 * @date 2023/7/12 16:58
 */
@Component
@Slf4j
public class StateMachineEngine  {

    private Map<String, StateMachineStrategy> stateMachineMap;

    @Autowired
    private ApplicationContext applicationContext;

    /**
     * 根据枚举获取状态机实例key
     *
     * @param stateMachineEnum stateMachineEnum
     * @return String
     */
    private String getMachineId(StateMachineEnum stateMachineEnum) {
        return stateMachineMap.get(stateMachineEnum.getCode()).getMachineType();
    }
    /**
     * 根据枚举获取状态机实例key
     * @return String
     */
    private String getMachine(String statMachineId) {
        return stateMachineMap.get(statMachineId).getMachineType();
    }
    /**
     * 根据枚举获取状态机示例，并根据当前状态、事件、上下文，进行状态流转
     *
     * @return AuditState
     */
    public ItsmState fire(ItsmState itsmState, ItsmEvent itsmEvent, ItsmContext itsmContext) {
        StateMachine<ItsmState, ItsmEvent, ItsmContext> stateMachine = StateMachineFactory.get(itsmContext.getInstId());
        ItsmState state = stateMachine.fireEvent(itsmState, itsmEvent, itsmContext);
        log.info("状态机：{}，当前状态：{}，事件：{}，上下文{}", stateMachine.getMachineId(), itsmState, itsmEvent, itsmContext);
        return state;
    }
    /**
     * 根据枚举获取状态机实例，并根据当前状态、事件、上下文，获取下一步的所有事件列表
     *
     * @return AuditState
     */
    public List<ItsmEvent> getNextEvents(AuditState itsmState, ItsmContext itsmContext) {
        StateMachine<ItsmState, ItsmEvent, ItsmContext> stateMachine = StateMachineFactory.get(itsmContext.getInstId());
        return stateMachine.getNextEvents(itsmState, itsmContext);
    }

    /**
     * 根据枚举获取状态机示例的状态DSL UML图
     * @return String
     */
    public String generateUml(ItsmContext itsmContext){
        StateMachine<ItsmState, ItsmEvent, ItsmContext> stateMachine = StateMachineFactory.get(itsmContext.getInstId());
        return stateMachine.generatePlantUML();
    }

    /**
     * 获取所有实现了接口的状态机
     */
    public void init() {
        Map<String, StateMachineStrategy> beansOfType = applicationContext.getBeansOfType(StateMachineStrategy.class);
        stateMachineMap = Optional.of(beansOfType)
                .map(beansOfTypeMap -> beansOfTypeMap.values().stream()
                        .filter(stateMachineHandler -> StringUtils.hasLength(stateMachineHandler.getMachineType()))
                        .collect(Collectors.toMap(StateMachineStrategy::getMachineType, Function.identity())))
                .orElse(new HashMap<>(8));
    }
}
